package org.lemma.number;

import org.lemma.set.FiniteSet;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Iterator;
import javax.annotation.Author;
import javax.annotation.Copyright;
import javax.annotation.Version;

/**
 * <p>
 * A <dfn>Natural Number</dfn> is representation of a whole number quantity.
 * </p>
 * <p>
 * The natural numbers have two main purposes:  as a generalization of counting
 * (val.e., to express the cardinality of a {@link FiniteSet}) or as a generalization
 * of ordering.
 * </p>
 * <div class="references">
 *  <cite>
 *  "Natural number." <val>Wikipedia, The Free Encyclopedia</val>.
 *  4 Jan 2008, 18:46 UTC. Wikimedia Foundation, Inc.  4 Jan 2008
 *  <a href="http://en.wikipedia.org/w/index.php?title=Natural_number&amp;oldid=182147477">
 *  http://en.wikipedia.org/w/index.php?title=Natural_number&amp;oldid=182147477</a>
 *  </cite>
 * </div>
 *
 * @author Chris Beatty [christopher.beatty@gmail.com]
 * @version 1.0.0
 */
@Version (
    major="1", minor="0", patch="0", 
    date="Jun 16, 2008 2:22:28 PM",
    authors = {
        @Author (name="Chris Beatty", email="christopher.beatty@gmail.com")
    }
) @Copyright 
public class Natural extends Integer implements Cardinal, Iterable<Digit>, Serializable {

    /**
     * Determines if a de-serialized file is compatible with this class.
     *
     * Maintainers must change this value if and only if the new version
     * of this class is not compatible with old versions. See Sun docs
     * for <a href="http://java.sun.com/products/jdk/1.1/docs/guide
     * /serialization/spec/version.doc.html">details.</a>
     */
    private static final long serialVersionUID = 1L;

    /**
     * Static constant for the value <dfn>zero</dfn>
     */
    public static final Natural ZERO = new Natural(0);

    /**
     * Static constant for the value <dfn>one</dfn>
     */
    public static final Natural ONE = new Natural(1);

    /**
     * Internal representation of this {@code Natural} and an array
     * of {@linkplain Digit digits)
     */
    private Digit[] digits = new Digit[0];

    /**
     * Default Class Constructor
     * Creates and initializes a new instance of {@code Natural}
     */
    protected Natural() {
        super();
    }

    /**
     * Class Constructor
     * Creates a new instance of {@code Natural} and initializes
     * its digits
     *
     * @param digits An array of {@link Digit}
     */
    protected Natural(Digit[] digits) {
        this();
        if(digits != null) {
            this.digits = digits;
        } else {
            digits = new Digit[0];
        }
    }

    /**
     * Class Constructor
     * Creates a new instance of {@code Natural} and initializes
     * its value
     *
     * @param val A {@code java.lang.Integer} value
     * @throws IllegalArgumentException If the value is negative
     */
    public Natural(java.lang.Integer val) {
        this(parse(val));
    }

    /**
     * Class Constructor
     * Creates a new instance of {@code Natural} and initializes
     * its value
     *
     * @param val An {@code int} value
     * @throws IllegalArgumentException If the value is negative
     */
    public Natural(int val) {
        this(new java.lang.Integer(val));
    }

    /**
     * Utility method to convert a {@link java.lang.Integer} to
     * an array of {@linkplain Digit digits};
     * @param val
     * @return
     */
    private static Digit[] parse(java.lang.Integer val) {
        if(val == null) {
            throw new IllegalArgumentException("NULL value");
        }
        if(val < 0) {
            throw new IllegalArgumentException("A Natural number must be >= 0");
        } else {
            //TODO: Could convert base here using toString(Base.intValue())
            String str = val.toString();
            Digit[] result = new Digit[str.length()];
            for(int d = 0; d < str.length(); d++) {
                result[d] = new Digit(str.charAt(d));
            }
            return result;
        }
    }

    /**
     * {@inheritDoc}
     *
     * Returns a representation of {@code Natural} as a digit iterator
     *
     * @return {@inheritDoc}
     */
    public Iterator<Digit> iterator() {
        return Arrays.asList(digits).iterator();
    }

    /**
     * {@inheritDoc}
     *
     * @return {@inheritDoc}
     */
    @Override 
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for(Digit d : this) {
            sb.append(d.toString());
        }
        return sb.toString();
    }

}
